#region Imported Namespaces
using System;
using System.Collections;
using System.Data;
using SqlClient=System.Data.SqlClient;

using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using DataAccess = PHSRAG.Utility.DataAccess;
using GenerateKey = PHSRAG.Insight21.BusinessObjects.ModuleKey;
#endregion 

namespace PHSRAG.Insight21.Humans
{
	/// <summary>
	/// Represents a device involved in a study
	/// Additional feature:
	///		-->Raises the request to the listAdditionRequests object for adding a new device to the legacy database.
	/// </summary>
	public class Device : BO.SmartBusinessObject
	{
		#region private instance variables
		private string name;
		private string commonName;
		private string manufacturer;
		#endregion

		#region private constant cacheKey(Devices)
		private static string DeviceKey = GenerateKey.MakeKey("DeviceKey_EA4D9A3F-575B-460b-BF0B-D3C51F1C0AB0",GenerateKey.Humans);
		#endregion
		
		#region private constants
		private const string ColumnDeviceItemCode="nItemCode";
		private const string ColumnDeviceName="sItemName";
		private const string ColumnDeviceCommonName="sGenericName";
		private const string ColumnDeviceManufacturer="sManufacturer";
		#endregion

		#region public device properties
		/// <summary>Gets/sets Device name </summary>
		public string Name
		{
			get {return name;}
			set {SetDirty( ref name, value);}
		}
		/// <summary>Gets/sets Device common name</summary>
		public string CommonName
		{
			get {return commonName;}
			set {SetDirty( ref commonName,value);}
		}
		/// <summary>Gets/sets Device Manufacturer</summary>
		public string Manufacturer
		{
			get {return manufacturer;}
			set {SetDirty( ref manufacturer,value);} 
		}
		
		/// <summary>
		/// Cache Key uniquely identifies this object within the cache.
		/// </summary>
		/// <returns>the unique string for this object.</returns>
		public override string CacheKey()
		{
			return DeviceKey;
		}
		#endregion
		
		#region caching
		/// <summary>
		/// Cache the current Object (Device)using the prevalent cache policy.
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache(DeviceKey, this);
		}

		/// <summary>
		/// Remove an object from the cache using the prevalent cache policy and its cacheKey .
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(DeviceKey);
		}
		#endregion

		#region constructor
		/// <summary>
		/// Constructs a new Device object based on the Cache Policy  and the datarow passed in as a parameter. 
		/// All the data members of the current object will be set to the values from the datarow.
		/// </summary>
		/// <param name="cachePolicy">available cache Policy</param>
		/// <param name="dataRow">The datarow passsed in as parameter</param>
		public Device(ICachePolicy cachePolicy, DataRow row):base(cachePolicy)
		{
			try
			{	
				PopulateDataMembers(row, (int)(row[ColumnDeviceItemCode]));
			}
			catch(Exception ex)
			{
				throw new Exception("Failed to create device object.", ex);
			}
		}

		/// <summary>
		/// Constructs a new device object based on the Cache Policy passed in as a parameter. 
		/// </summary>
		/// <param name="cachePolicy">available cahche policy</param>
		public Device(ICachePolicy cachePolicy) : base(cachePolicy)
		{
		
		}
		#endregion

		#region public Methods
		/// <summary>
		/// Adds the device to the Legacy database and adds a addition request for the device to the Insight database
		/// </summary>
		/// <param name="conn">Insight Connection string</param>
		/// <param name="rexConnection">Legacy database connection string</param>
		/// <param name="protocolProcessId">Protocol process Id to which the device is added</param>
		/// <returns>The id of the new device inserted</returns>
		public int AddRequest(string conn,string rexConnection,int protocolProcessId)
		{
			SqlClient.SqlConnection connection = new SqlClient.SqlConnection(rexConnection);
			SqlClient.SqlTransaction transaction = null;
			try
			{   
				connection.Open();
				transaction = connection.BeginTransaction( System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
				Save(transaction);
				ListAdditionRequest newDevice = new ListAdditionRequest(CachePolicy, "Device", Id.ToString(), name, protocolProcessId);
				newDevice.Save(conn);
				transaction.Commit();
				return newDevice.Id;
			}
			catch(Exception ex)
			{
				if( transaction != null )
				{
					transaction.Rollback();
				}
				throw new Exception("Failed to add drug request.", ex);
			}
			finally
			{	
				
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
		}
		#endregion
				
		#region protected override methods

		/// <summary>Saves the device item</summary>
		/// <param name="sqlTransaction">Information to connect to the database</param>
		protected override void SaveObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			//Don't have a field in the UI for the "note" and "deviceType". As such, passing in nulls.
			try
			{
				Id=Convert.ToInt32(DataAccess.ExecuteScalar(sqlTransaction.Connection, sqlTransaction, "spDeviceMaintUpdate", 
					DataAccess.BuildSqlParameterArray(
					"@nItemCode", SqlDbType.Int,Id,
					"@sItemName",SqlDbType.VarChar,(null==name)?DBNull.Value:(object)name,
					"@sGenericName",SqlDbType.VarChar,(null==commonName)?DBNull.Value:(object)commonName,
					"@sManufacturer",SqlDbType.VarChar,(null==manufacturer)?DBNull.Value:(object)manufacturer,
					"@sDeviceType",SqlDbType.VarChar,DBNull.Value,
					"@sNote",SqlDbType.VarChar,DBNull.Value ) ) );
			}
			catch(Exception ex)
			{
				throw new Exception("Failed to save Device.", ex);
			}
		}

		/// <summary>
		/// Deletes a Device. This method is not currently implemented.
		/// </summary>
		/// <param name="sqlTransaction">DB Transaction to use during deletion.</param>
		protected override void DeleteObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			throw new Exception("Device.DeleteObject is not yet implemented.");
		}

		/// <summary>Loads the device object with the specified item code</summary>
		/// <param name="rexConnection">Legacy database connection string</param>
		/// <param name="args">ItemCode of the drug to be loaded</param>
		public override void Load(string rexConnection, params object[] args)
		{
			try
			{
				if (args.Length != 1)
				{
					throw new Exception("Device.Load() requires only Id as parameter");
				}
				else 
				{
					DataTable dataTable = DataAccess.GetDataTable(rexConnection, "spDeviceMaintGet",
						DataAccess.BuildSqlParameterArray("@nItemCode", SqlDbType.Int, (int)args[0]));
					
					//since the stored procedure does not return the itemcode as one of the output,the inparameter is assigned.
					if((dataTable!=null) && (dataTable.Rows.Count!=0)){PopulateDataMembers(dataTable.Rows[0],(int)args[0]);}
				}						
			}
			catch(Exception ex)
			{
				throw new Exception("Failed to load Device.", ex);
			}
		}
		#endregion

		#region private methods
		/// <summary>
		/// Converts a database column value to a string
		/// </summary>
		/// <param name="columnValue">Value from the database</param>
		/// <returns>An equivalent string</returns>
		private string GetColumnValue(object columnValue)
		{
			return (columnValue == DBNull.Value) ? string.Empty : columnValue.ToString();
		}

		/// <summary>Sets the device instance members  </summary>
		/// <param name="deviceRow">device item values for a deviceId</param>
		/// <param name="itemCode">itemcode for the device</param>
		private void PopulateDataMembers(DataRow deviceRow, int itemCode)
		{
			try
			{
				Id = itemCode;
				name = GetColumnValue(deviceRow[ColumnDeviceName]);
				commonName = GetColumnValue(deviceRow[ColumnDeviceCommonName]);
				manufacturer = GetColumnValue(deviceRow[ColumnDeviceManufacturer]);
			}
			catch (Exception ex)
			{
				throw new Exception("Failed to populate Device members.", ex);
			}
		}
		#endregion

	}
}

